home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SOURCE.ZIP / KEEPER.ASM < prev    next >
Assembly Source File  |  1986-02-05  |  23KB  |  484 lines

  1. VECTORS SEGMENT AT 0H           ;Set up segment to intercept Interrupts
  2.         ORG     9H*4            ;The keyboard Interrupt
  3. KEYBOARD_INT     LABEL   DWORD
  4.         ORG     1CH*4           ;Timer Interrupt
  5. TIMER_VECTOR      LABEL   DWORD
  6. VECTORS ENDS
  7.  
  8. SCREEN  SEGMENT AT 0B000H       ;A dummy segment to use as the
  9. SCREEN  ENDS                    ;Extra Segment 
  10.  
  11. ROM_BIOS_DATA   SEGMENT AT 40H  ;BIOS statuses held here, also keyboard buffer
  12.  
  13.         ORG     1AH
  14.         HEAD DW      ?                  ;Unread chars go from Head to Tail
  15.         TAIL DW      ?
  16.         BUFFER       DW      16 DUP (?)         ;The buffer itself
  17.         BUFFER_END   LABEL   WORD
  18.  
  19. ROM_BIOS_DATA   ENDS
  20.  
  21. CODE_SEG        SEGMENT
  22.         ASSUME  CS:CODE_SEG
  23.         ORG     100H            ;ORG = 100H to make this into a .COM file
  24. FIRST:  JMP     LOAD_KEEPER        ;First time through 
  25.  
  26.         COPY_RIGHT      DB      '(C)1985 S.HOLZNER' ;Ascii autograph
  27.         PAD             DB      20*102 DUP(0)       ;Memory storage for pad  
  28.         PAD_CURSOR      DW      9*102               ;Current position in pad
  29.         ATTRIBUTE       DB      112             ;Pad Attribute -- reverse video
  30.         LINE_ATTRIBUTE  DB      240             ;Flashing Rev video
  31.         OLD_ATTRIBUTE   DB      7               ;Original screen attrib: normal
  32.         PAD_OFFSET      DW      0               ;Chooses 1st 250 bytes or 2nd
  33.         FIRST_POSITION  DW      ?               ;Position of 1st char on screen
  34.         TRIGGER_FLAG    DW      0               ;Trigger on or off
  35.         FULL_FLAG       DB      0               ;Buffer Full Flag
  36.         LINE            DW      9               ;Line number, 0-9
  37.         SCREEN_SEG_OFFSET       DW      0       ;0 for mono, 8000H for graphics
  38.         IO_CHAR         DW      ?               ;Holds addr of Put or Get_Char
  39.         STATUS_PORT     DW      ?               ;Video controller status port
  40.         OLD_KEYBOARD_INT        DD      ?       ;Location of old kbd interrupt
  41.         FINISHED_FLAG           DB      1       ;If not finished,f buffer 
  42.         COMMAND_INDEX           DW      1       ;Stores positior timer)
  43.         ROM_TIMER               DD      1       ;The Timer interrupt's address
  44.         OLD_HEAD        DW      0
  45.  
  46. KEEPER   PROC    NEAR            ;The keyboard interrupt will now come here.
  47.         ASSUME  CS:CODE_SEG
  48.         PUSH    AX              ;Save the used registers for good form
  49.         PUSH    BX
  50.         PUSH    CX
  51.         PUSH    DX
  52.         PUSH    DI
  53.         PUSH    SI
  54.         PUSH    DS
  55.         PUSH    ES
  56.         PUSHF                           ;First, call old keyboard interrupt
  57.         CALL    OLD_KEYBOARD_INT
  58.         ASSUME  DS:ROM_BIOS_DATA        ;Examine the char just put in
  59.         MOV     BX,ROM_BIOS_DATA
  60.         MOV     DS,BX
  61.         MOV     BX,TAIL                 ;Point to current tail
  62.         CMP     BX,HEAD                 ;If at head, kbd int has deleted char
  63.         JE      BYE                     ;So leave 
  64.         MOV     DX,HEAD
  65.         SUB     DX,2                    ;Point to just read in character
  66.         CMP     DX,OFFSET BUFFER        ;Did we undershoot buffer?
  67.         JAE     NOWRAP                  ;Nope
  68.         MOV     DX,OFFSET BUFFER_END    ;Yes -- move to buffer top
  69.         SUB     DX,2                    ;Compare two bytes back from head
  70. NOWRAP: CMP     DX,TAIL                 ;If it's the tail, buffer is full
  71.         JNE     NOTFULL                 ;We're OK, jump to NotFull
  72.         CMP     FULL_FLAG,1             ;Check if keyboard buffer full
  73.         JE      BYE                     ;Yep, leave
  74.         MOV     FULL_FLAG,1             ;Oops, full, set flag and take
  75.         JMP     CHK                     ; this last character
  76. NOTFULL:MOV     FULL_FLAG,0             ;Always reset Full_Flag when buff clears
  77. CHK:    CMP     TRIGGER_FLAG,0          ;Is the window on (triggered?)
  78.         JNE     SUBT                    ;Yep, keep going
  79.         MOV     DX,OLD_HEAD             ;Check position of buffer head
  80.         CMP     DX,HEAD
  81.         JNE     CONT
  82.         MOV     OLD_HEAD,0
  83. BYE:    JMP     OUT
  84. CONT:   MOV     DX,HEAD
  85.         MOV     OLD_HEAD,DX
  86. SUBT:   SUB     BX,2                    ;Point to just read in character
  87.         CMP     BX,OFFSET BUFFER        ;Did we undershoot buffer?
  88.         JAE     NO_WRAP                 ;Nope
  89.         MOV     BX,OFFSET BUFFER_END    ;Yes -- move to buffer top
  90.         SUB     BX,2                    ;
  91. NO_WRAP:MOV     DX,[BX]                 ;Char in DX now        
  92.         ;------ CHAR IN DX NOW -------
  93.         CMP     FINISHED_FLAG,0
  94.         JE      IN             
  95.         CMP     DX,310EH                ;Default trigger is a ^N here.
  96.         JNE     NOT_TRIGGER             ;No
  97.         MOV     TAIL,BX
  98.         NOT     TRIGGER_FLAG            ;Switch Modes
  99.         CMP     TRIGGER_FLAG,0          ;Trigger off?
  100.         JNE     TRIGGER_ON              ;No, only other choice is on
  101. TRIGGER_OFF:
  102.         MOV     OLD_HEAD,0              ;Reset old head
  103.         MOV     AH,OLD_ATTRIBUTE        ;Get ready to restore screen
  104.         MOV     ATTRIBUTE,AH            ;Pad and blinking line set to orig.
  105.         MOV     LINE_ATTRIBUTE,AH       ; values
  106.         MOV     PAD_OFFSET,10*102       ;Point to 2nd half of pad
  107.         LEA     AX,PUT_CHAR             ;Make IO call Put_Char as it scans
  108.         MOV     IO_CHAR,AX              ;over all locations in pad on screen
  109.         CALL    IO                      ;Restore screen
  110.         CMP     LINE,9                  ;Was the window turned off without
  111.         JE      IN                      ; using up-down keys? If so, exit
  112.         MOV     AX,LINE                 ;No, there is a line to stuff in
  113.         MOV     CL,102                  ; keyboard buffer
  114.         MUL     CL                      ;Find its location in Pad
  115.         MOV     COMMAND_INDEX,AX        ;And send to Put
  116.         CALL    PUT                     ;Which will do actual stuffing
  117. IN:     JMP     OUT                     ;Done
  118. TRIGGER_ON:                             ;Window just turned on
  119.         MOV     LINE,9                  ;Set blinking line to bottom
  120.         MOV     PAD_OFFSET,10*102       ;Point to screen storage part of pad
  121.         LEA     AX,GET_CHAR             ;Make IO use Get_char so current screen
  122.         MOV     IO_CHAR,AX              ;is stored
  123.         CALL    IO                      ;Store Screen
  124.         CALL    DISPLAY                 ;And put up the pad
  125.         JMP     OUT                     ;Done here.
  126. NOT_TRIGGER:
  127.         TEST    TRIGGER_FLAG,1          ;Is Trigger on?
  128.         JZ      RUBOUT_TEST
  129.         MOV     TAIL,BX                 ;Yes, delete this char from buffer
  130. UP:     CMP     DX,4800H                ;An Up cursor key?
  131.         JNE     DOWN                    ;No, try Down
  132.         DEC     LINE                    ;Move blinker up one line
  133.         CMP     LINE,0                  ;At top? If so, reset
  134.         JGE     NOT_TOP
  135.         MOV     LINE,9
  136. NOT_TOP:CALL    DISPLAY                 ;Display result
  137.         JMP     OUT                     ;And leave
  138. DOWN:   CMP     DX,5000H                ;Perhaps Down cusor key pushed
  139.         JNE     IN                      ;If not, ignore key
  140.         INC     LINE                    ;If so, move down one
  141.         CMP     LINE,9                  ;If at bottom, wrap to top
  142.         JLE     NOT_BOT
  143.         MOV     LINE,0
  144. NOT_BOT:CALL    DISPLAY                 ;Show results
  145.         JMP     OUT                     ;And exit
  146. RUBOUT_TEST:
  147.         CMP     DX,0E08H                ;Is it a Rubout?
  148.         JNE     CHAR_TEST               ;No -- try carriage return-line feed
  149.         MOV     BX,PAD_CURSOR           ;Yes -- get current pad location
  150.         CMP     BX,9*102                ;Are we at beginning of last line?
  151.         JLE     NEVER_MIND              ;Yes -- can't rubout past beginning
  152.         SUB     PAD_CURSOR,2            ;No, rubout this char
  153.         MOV     PAD[BX-2],20H           ;Move a space in instead (3920H)
  154.         MOV     PAD[BX-1],39H
  155. NEVER_MIND:
  156.         JMP     OUT                     ;Done here.
  157. CHAR_TEST:
  158.         CMP     DL,13                   ;Is this a carriage return?
  159.         JE      PLUG                    ;If yes, plug this line into Pad
  160.         CMP     DL,32                   ;If this char < Ascii 32, delete line
  161.         JGE     PLUG
  162.         MOV     PAD_CURSOR,9*102        ;Clear the current line
  163.         MOV     CX,51
  164.         MOV     BX,9*102
  165. CLEAR:  MOV     WORD PTR PAD[BX],0
  166.         ADD     BX,2
  167.         LOOP    CLEAR
  168.         JMP     OUT                     ;And exit
  169.  
  170. PLUG:   MOV     BX,PAD_CURSOR           ;Get current pad location
  171.         CMP     BX,10*102-2             ;Are we past the end of the pad?
  172.         JGE     CRLF_TEST               ;Yes -- throw away char
  173.         MOV     WORD PTR PAD[BX],DX     ;No -- move ASCII code into pad
  174.         ADD     PAD_CURSOR,2            ;Increment pad location
  175. CRLF_TEST:
  176.         CMP     DX,1C0DH                ;Is it a carriage return-line feed?
  177.         JNE     OUT                     ;No -- put it in the pad
  178.         CALL    CRLF                    ;Yes -- move everything up in pad
  179. OUT:    POP     ES                      ;Having done Pushes, here are the Pops
  180.         POP     DS
  181.         POP     SI
  182.         POP     DI
  183.         POP     DX
  184.         POP     CX
  185.         POP     BX
  186.         POP     AX     
  187.         IRET                    ;An interrupt needs an IRET
  188. KEEPER   ENDP
  189.  
  190. DISPLAY PROC    NEAR                    ;Puts the whole pad on the screen
  191.         PUSH    AX
  192.         MOV     ATTRIBUTE,112           ;Use reverse video
  193.         MOV     LINE_ATTRIBUTE,240
  194.         MOV     PAD_OFFSET,0            ;Use 1st 250 bytes of pad memory
  195.         LEA     AX,PUT_CHAR             ;Make IO use Put-Char so it does
  196.         MOV     IO_CHAR,AX              
  197.         CALL    IO                      ;Put result on screen
  198.         POP     AX
  199.         RET                             ;Leave
  200. DISPLAY ENDP
  201.  
  202. CRLF    PROC    NEAR                    ;This handles carriage returns
  203.         PUSH    BX                      ;Push everything conceivable
  204.         PUSH    CX           
  205.         PUSH    DI
  206.         PUSH    SI
  207.         PUSH    DS
  208.         PUSH    ES   
  209.         ASSUME  DS:CODE_SEG             ;Set DS to Code_Seg here
  210.         PUSH    CS
  211.         POP     DS
  212.         ASSUME  ES:CODE_SEG             ;And ES too
  213.         PUSH    DS
  214.         POP     ES
  215.         LEA     DI,PAD                  ;Get ready to move contents of Pad
  216.         MOV     SI,DI                   ; up one line
  217.         ADD     SI,102                  ;DI-top line, SI-one below top line
  218.         MOV     CX,9*51
  219.         MOV     BX,PAD_CURSOR           ;But first finish line with a 0        
  220.         CMP     BX,9*102+2              ; as a flag letting Put know line is
  221.         JE      POPS                    ; done.
  222.         MOV     WORD PTR PAD[BX],0
  223. REP     MOVSW                           ;Move up Pad contents
  224.         MOV     CX,51                   ;Now fill the last line with spaces
  225.         MOV     AX,3920H
  226. REP     STOSW                           ;Using Stosw
  227. POPS:   MOV     PAD_CURSOR,9*102        ;And finally reset Cursor to beginning
  228.         POP     ES                      ; of the last line again.
  229.         POP     DS
  230.         POP     SI
  231.         POP     DI
  232.         POP     CX
  233.         POP     BX
  234. DONE:   RET                             ;And out.
  235. CRLF    ENDP
  236.  
  237. GET_CHAR        PROC    NEAR    ;Gets a char from screen and advances position
  238.         ASSUME  ES:SCREEN,DS:ROM_BIOS_DATA
  239.         PUSH    DX
  240.         MOV     SI,2            ;Loop twice, once for char, once for attribute
  241.         MOV     DX,STATUS_PORT  ;Get ready to read video controller status
  242. G_WAIT_LOW:                     ;Start waiting for a new horizontal scan -
  243.         IN      AL,DX           ;Make sure the video controller scan status
  244.         TEST    AL,1            ;is low
  245.         JNZ     G_WAIT_LOW
  246. G_WAIT_HIGH:                    ;After port has gone low, it must go high
  247.         IN      AL,DX           ;before it is safe to read directly from
  248.         TEST    AL,1            ;the screen buffer in memory
  249.         JZ      G_WAIT_HIGH
  250.         MOV     AH,ES:[DI]      ;Do the move from the screen, one byte at a time
  251.         INC     DI              ;Move to next screen location                   
  252.         DEC     SI              ;Decrement loop counter
  253.         CMP     SI,0            ;Are we done?
  254.         JE      LEAVE           ;Yes
  255.         MOV     PAD[BX],AH      ;No -- put char we got into the pad
  256.         JMP     G_WAIT_LOW      ;Do it again
  257. LEAVE:  MOV     OLD_ATTRIBUTE,AH
  258.         ADD     BX,2
  259.         POP     DX
  260.         RET
  261. GET_CHAR        ENDP
  262.  
  263. PUT_CHAR        PROC    NEAR    ;Puts one char on screen and advances position
  264.         PUSH    DX
  265.         MOV     AH,PAD[BX]      ;Get the char to be put onto the screen
  266.         CMP     AH,32
  267.         JAE     GO
  268.         MOV     AH,32
  269. GO:     MOV     SI,2            ;Loop twice, once for char, once for attribute
  270.         MOV     DX,STATUS_PORT  ;Get ready to read video controller status
  271. P_WAIT_LOW:                     ;Start waiting for a new horizontal scan -
  272.         IN      AL,DX           ;Make sure the video controller scan status
  273.         TEST    AL,1            ;is low
  274.         JNZ     P_WAIT_LOW
  275. P_WAIT_HIGH:                    ;After port has gone low, it must go high
  276.         IN      AL,DX           ;before it is safe to write directly to
  277.         TEST    AL,1            ;the screen buffer in memory
  278.         JZ      P_WAIT_HIGH
  279.         MOV     ES:[DI],AH      ;Move to screen, one byte at a time
  280.         MOV     AH,ATTRIBUTE    ;Load attribute byte for second pass
  281.         INC     DI              ;Point to next screen postion
  282.         DEC     SI              ;Decrement loop counter
  283.         JNZ     P_WAIT_LOW      ;If not zero, do it one more time
  284.         ADD     BX,2
  285.         POP     DX
  286.         RET                     ;Exeunt
  287. PUT_CHAR        ENDP
  288.  
  289. IO      PROC    NEAR            ;This scans over all screen positions of the pad
  290.         ASSUME  ES:SCREEN       ;Use screen as extra segment
  291.         MOV     BX,SCREEN
  292.         MOV     ES,BX
  293.         
  294.         PUSH    DS
  295.         MOV     BX,ROM_BIOS_DATA
  296.         MOV     DS,BX
  297.         MOV     BX,4AH
  298.         MOV     BX,DS:[BX]
  299.         SUB     BX,51
  300.         ADD     BX,BX
  301.         MOV     FIRST_POSITION,BX
  302.         POP     DS
  303.  
  304.         MOV     DI,SCREEN_SEG_OFFSET    ;DI will be pointer to screen postion
  305.         ADD     DI,FIRST_POSITION       ;Add width of screen minus pad width
  306.         MOV     BX,PAD_OFFSET           ;BX will be pad location pointer
  307.         MOV     CX,10                   ;There will be 10 lines
  308.  
  309. LINE_LOOP:      
  310.         PUSH    WORD PTR ATTRIBUTE
  311.         PUSH    CX                      ;Figure out whether this is blinking 
  312.         NEG     CX                      ; line and if so, temporarily change
  313.         ADD     CX,10                   ; display attribute
  314.         CMP     CX,LINE
  315.         JNE     NOLINE
  316.         MOV     CL,LINE_ATTRIBUTE
  317.         MOV     ATTRIBUTE,CL
  318. NOLINE: POP     CX
  319.         MOV     DX,51                   ;And 51 spaces across
  320. CHAR_LOOP:
  321.         CALL    IO_CHAR                 ;Call Put-Char or Get-Char
  322.         DEC     DX                      ;Decrement character loop counter
  323.         JNZ     CHAR_LOOP               ;If not zero, scan over next character
  324.         ADD     DI,FIRST_POSITION       ;Add width of screen minus pad width
  325.                          
  326.         POP     WORD PTR ATTRIBUTE
  327.         LOOP    LINE_LOOP               ;And now go back to do next line
  328.         RET                             ;Finished
  329. IO      ENDP
  330.  
  331. PUT  PROC    NEAR    ;Here it is.             
  332.         ASSUME  DS:ROM_BIOS_DATA      ;Free DS
  333.         PUSH    DS                    ;Save all used registers
  334.         PUSH    SI
  335.         PUSH    DI
  336.         PUSH    DX
  337.         PUSH    CX
  338.         PUSH    BX
  339.         PUSH    AX
  340.         MOV     AX,ROM_BIOS_DATA        ;Just to make sure
  341.         MOV     DS,AX                   ;Set DS correctly
  342. FIN:    MOV     FINISHED_FLAG,1         ;Assume we'll finish
  343.         MOV     BX,TAIL                 ;Prepare to move to buffer's tail
  344.         MOV     SI,COMMAND_INDEX        ;Get our source index
  345.  
  346. STUFF:  MOV     AX,WORD PTR PAD[SI]
  347.         ADD     SI,2                    ;Point to the command's next character
  348.         CMP     AX,0                    ;Is it a zero? (End of command)
  349.         JE      NO_NEW_CHARACTERS       ;Yes, leave with Finished_Flag=1
  350.         MOV     DX,BX                   ;Find position in buffer from BX
  351.         ADD     DX,2                    ;Move to next position for this word
  352.         CMP     DX,OFFSET BUFFER_END ;Are we past the end?
  353.         JL      NO_WRAP2                ;No, don't wrap
  354.         MOV     DX,OFFSET BUFFER        ;Wrap
  355. NO_WRAP2:
  356.         CMP     DX,HEAD                 ;Buffer full but not yet done?
  357.         JE      BUFFER_FULL             ;Time to leave, set Finished_Flag=0.
  358.         ADD     COMMAND_INDEX,2         ;Move to next word in command
  359.         MOV     [BX],AX                 ;Put it into the buffer right here.
  360.         ADD     BX,2                    ;Point to next space in buffer
  361.         CMP     BX,OFFSET BUFFER_END ;Wrap here?
  362.         JL      NO_WRAP3                ;No, readjust buffer tail
  363.         MOV     BX,OFFSET BUFFER        ;Yes, wrap
  364. NO_WRAP3: 
  365.         MOV     TAIL,BX                 ;Reset buffer tail
  366.         JMP     STUFF                   ;Back to stuff in another character.
  367. BUFFER_FULL:                            ;If buffer is full, let timer take over
  368.         MOV     FINISHED_FLAG,0         ; by setting Finished_Flag to 0.
  369. NO_NEW_CHARACTERS:
  370.         POP     AX                      ;Restore everything before departure.
  371.         POP     BX
  372.         POP     CX
  373.         POP     DX
  374.         POP     DI
  375.         POP     SI
  376.         POP     DS
  377.         STI
  378.         RET
  379. PUT  ENDP
  380.  
  381.         ASSUME  DS:CODE_SEG
  382. INTERCEPT_TIMER   PROC    NEAR          ;This completes filling the buffer
  383.         PUSHF                           ;Store used flags
  384.         PUSH    DS                      ;Save DS since we'll change it
  385.         PUSH    CS                      ;Put current value of CS into DS
  386.         POP     DS
  387.         CALL    ROM_TIMER               ;Make obligatory call
  388.         PUSHF
  389.         CMP     FINISHED_FLAG,1         ;Do we have to do anything?
  390.         JE      OUT1                     ;No, leave
  391.         CLI                             ;Yes, start by clearing interrupts
  392.         PUSH    DS                      ;Save these.
  393.         PUSH    SI
  394.         PUSH    DX
  395.         PUSH    BX
  396.         PUSH    AX
  397.         ASSUME  DS:ROM_BIOS_DATA        ;Point to the keyboard buffer again.
  398.         MOV     AX,ROM_BIOS_DATA
  399.         MOV     DS,AX
  400.         MOV     BX,TAIL                 ;Prepare to put characters in at tail
  401.         MOV     FINISHED_FLAG,1         ;Assume we'll finish
  402.         MOV     SI,COMMAND_INDEX        ;Find where we left ourselves
  403.  
  404. STUFF2: MOV     AX,WORD PTR PAD[SI]     ;The same stuff loop as above.
  405.         ADD     SI,2                    ;Point to next command character.
  406.         CMP     AX,0                    ;Is it zero? (end of command)
  407.         JNE     OVER                    ;No, continue.
  408.         JMP     NO_NEW_CHARACTERS2      ;Yes, leave with Finished_Flag=1
  409. OVER:   MOV     DX,BX                   ;Find position in buffer from BX
  410.         ADD     DX,2                    ;Move to next position for this word
  411.         CMP     DX,OFFSET BUFFER_END    ;Are we past the end?
  412.         JL      NO_WRAP4                ;No, don't wrap
  413.         MOV     DX,OFFSET BUFFER        ;Do the Wrap rap.
  414. NO_WRAP4:                               
  415.         CMP     DX,HEAD                 ;Buffer full but not yet done?
  416.         JE      BUFFER_FULL2            ;Time to leave, come back later.
  417.         ADD     COMMAND_INDEX,2         ;Point to next word of command.
  418.         MOV     [BX],AX                 ;Put into buffer
  419.         ADD     BX,2                    ;Point to next space in buffer
  420.         CMP     BX,OFFSET BUFFER_END    ;Wrap here?
  421.         JL      NO_WRAP5                ;No, readjust buffer tail
  422.         MOV     BX,OFFSET BUFFER        ;Yes, wrap
  423. NO_WRAP5:                               
  424.         MOV     TAIL,BX                 ;Reset buffer tail
  425.         JMP     STUFF2                  ;Back to stuff in another character
  426. BUFFER_FULL2:
  427.         MOV     FINISHED_FLAG,0         ;Set flag to not-done-yet.
  428. NO_NEW_CHARACTERS2:
  429.         POP     AX                      ;Restore these.
  430.         POP     BX
  431.         POP     DX
  432.         POP     SI
  433.         POP     DS
  434. OUT1:   POPF                            ;And Exit.
  435.         POP     DS
  436.         IRET                            ;With customary IRET
  437. INTERCEPT_TIMER   ENDP
  438.  
  439. LOAD_KEEPER        PROC    NEAR    ;This procedure intializes everything
  440.         ASSUME  DS:VECTORS   ;The data segment will be the Interrupt area
  441.         MOV     AX,VECTORS
  442.         MOV     DS,AX
  443.         
  444.         MOV     AX,KEYBOARD_INT         ;Get the old interrupt service routine
  445.         MOV     OLD_KEYBOARD_INT,AX     ;address and put it into our location
  446.         MOV     AX,KEYBOARD_INT[2]      ;OLD_KEYBOARD_INT so we can call it.
  447.         MOV     OLD_KEYBOARD_INT[2],AX
  448.         
  449.         MOV     KEYBOARD_INT,OFFSET KEEPER  ;Now load the address of our notepad
  450.         MOV     KEYBOARD_INT[2],CS         ;routine into the keyboard interrupt
  451.                                         
  452.         MOV     AX,TIMER_VECTOR         ;Now same for timer
  453.         MOV     ROM_TIMER,AX
  454.         MOV     AX,TIMER_VECTOR[2]
  455.         MOV     ROM_TIMER[2],AX
  456.  
  457.         MOV     TIMER_VECTOR,OFFSET INTERCEPT_TIMER
  458.         MOV     TIMER_VECTOR[2],CS      ;And intercept that too.
  459.  
  460.         ASSUME  DS:ROM_BIOS_DATA
  461.         MOV     AX,ROM_BIOS_DATA
  462.         MOV     DS,AX
  463.         MOV     BX,OFFSET BUFFER     ;Clear the keyboard buffer.
  464.         MOV     HEAD,BX
  465.         MOV     TAIL,BX
  466.         MOV     AH,15                   ;Ask for service 15 of INT 10H 
  467.         INT     10H                     ;This tells us how display is set up
  468.         MOV     STATUS_PORT,03BAH        ;Assume this is a monochrome display
  469.         TEST    AL,4                    ;Is it?
  470.         JNZ     EXIT                    ;Yes - jump out
  471.         MOV     SCREEN_SEG_OFFSET,8000H ;No - set up for graphics display
  472.         MOV     STATUS_PORT,03DAH
  473.  
  474. EXIT:   MOV     DX,OFFSET LOAD_KEEPER      ;Set up everything but LOAD_PAD to
  475.         INT     27H                     ;stay and attach itself to DOS
  476. LOAD_KEEPER        ENDP
  477.  
  478.         CODE_SEG        ENDS
  479.         
  480.         END     FIRST   ;END "FIRST" so 8088 will go to FIRST first.
  481.  
  482.  
  483.  
  484.